/*  
	------------------------------------------------------------------------
	 NQ Core Library
	
	 Homepage: http://www.awzhome.de/
	------------------------------------------------------------------------
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of NQ Core Library.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	------------------------------------------------------------------------
*/

namespace AWZhome.NQ.Core
{
	/// <summary>
	/// Interface for the service factory class which is responsible for managing all services at runtime.
	/// </summary>
	/// <remarks>
	/// Usually it's enough to use the standard implementation of this interface by instancing
	/// <see cref="AWZhome.NQ.Core.NQServiceManager">NQServiceManager</see> class.
	/// </remarks>
	public interface INQServiceManager
	{
		/// <summary>
		/// Fires when a new service object is created.
		/// </summary>
		/// <remarks>
		/// A reference to the service object can be found in the
		/// <see cref="AWZhome.NQ.Core.NQServiceCreatedEventArgs">NQServiceCreatedEventArgs</see> parameter.
		/// </remarks>
		event NQServiceCreatedEventHandler ServiceCreated;

		/// <summary>
		/// Fires when a service instance is destroyed.
		/// </summary>
		event NQServiceDestroyedEventHandler ServiceDestroyed;

		/// <summary>
		/// Fired when a message is logged.
		/// </summary>
		event NQLogEventHandler MessageLogged;

		/// <summary>
		/// Fired when the <see cref="AWZhome.NQ.Core.INQServiceManager.ExitApplication">ExitApplication</see>
		/// method is called.
		/// </summary>
		/// <remarks>
		/// Other parts of the application can react to the event and perform some cleaning operations.
		/// By setting the <see cref="AWZhome.NQ.Core.NQCancelEventArgs.Cancel">Cancel</see> property
		/// to <c>true</c> the exit can be cancelled. This has to be done for GUI applications that
		/// should perform a regular exit from the window message loop instead of directly exiting the
		/// process.
		/// </remarks>
		event System.EventHandler<NQCancelEventArgs> AppExitRequested;

		/// <summary>
		/// Retrieves the value of a command line parameter.
		/// </summary>
		/// <param name="paramname">Parameter name, without prefixes like <c>/</c> or <c>-</c>.</param>
		/// <returns>A string array with parameter data (a file name, for example).</returns>
		/// <remarks>
		/// The standard implementation <see cref="AWZhome.NQ.Core.NQServiceManager">NQServiceManager</see> assumes the command
		/// line parameters to be of following format:
		/// <code>app.exe -p1 data1 data2 -p2 data3 -p3 -p4</code>
		/// where <c>-p1</c> to <c>-p4</c> are the parameter names and <c>data1</c> to <c>data4</c> the parameter data.
		/// </remarks>
		string[] GetCmdLineParam(string paramname);

		/// <summary>
		/// Checks if a command-line parameter is set.
		/// </summary>
		/// <param name="paramname">Parameter name, without prefixes like <c>/</c> or <c>-</c>.</param>
		/// <returns><c>True</c>, if command-line parameter is set, <c>false</c> otherwise.</returns>
		bool IsCmdLineParamSet(string paramname);

		/// <summary>
		/// Retrieves an instance of a multi-instance service object.
		/// </summary>
		/// <typeparam name="T">Type of the retrieved service instance.</typeparam>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <returns>Instance of the service object, typed as set by the <typeparamref name="T">T</typeparamref> parameter.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only. Please use
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.GetService">GetService</see> for single-instance services.
		/// </para>
		/// <para>
		/// <c>CreateService</c> resolves any service substitutes. So if the requested
		/// service has been substituted by another service, this method will return an instance of that substituting service.
		/// </para>
		/// </remarks>
		T CreateService<T>(System.Type serviceInterface);

		/// <summary>
		/// Retrieves an instance of a multi-instance dependent service object and passes its
		/// parent service through its constructor.
		/// </summary>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <typeparam name="S">Type of parent service given by <paramref cref="dependent">dependent</paramref>.</typeparam>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <param name="dependent">Instance of the parent service the created service depends on.</param>
		/// <returns>Instance of the service object, typed as set by the <typeparamref name="T">T</typeparamref> parameter.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only. Please use
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.GetService">GetService</see> for single-instance services.
		/// </para>
		/// <para>
		/// <c>CreateService</c> resolves any service substitutes. So if the requested
		/// service has been substituted by another service, this method will return an instance of that substituting service.
		/// </para>
		/// </remarks>
		T CreateDependentService<T, S>(System.Type serviceInterface, S dependent);

		/// <summary>
		/// Retrieves an instance of a multi-instance dependent service object and passes its two
		/// parent services through its constructor.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <param name="dep1">Instance of the first parent service the created service depends on.</param>
		/// <param name="dep2">Instance of the second parent service the created service depends on.</param>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <typeparam name="S1">Type of the first parent service given by <paramref cref="dep1">dep1</paramref>.</typeparam>
		/// <typeparam name="S2">Type of the second parent service given by <paramref cref="dep2">dep2</paramref>.</typeparam>
		/// <returns>Instance of the service object.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only. Please use
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.GetService">GetService</see> for single-instance services.
		/// </para>
		/// <para>
		/// <c>CreateService</c> resolves any service substitutes (see also
		/// <see cref="AWZhome.NQ.Core.NQServiceSubstituteAttribute">NQServiceSubstituteAttribute</see>). So if the requested
		/// service has been substituted by another service, this method will return an instance of that substituting service.
		/// </para>
		/// </remarks>
		T CreateDependentService2<T, S1, S2>(System.Type serviceInterface, S1 dep1, S2 dep2);

		/// <summary>
		/// Directly retrieves an instance of a multi-instance service object.
		/// </summary>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <returns>Instance of the service object.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only.
		/// </para>
		/// <para>
		/// <c>CreateServiceDirect</c> ignores any service substitutes, what means that the resulting object instance always will
		/// be of the requested service.
		/// </para>
		/// </remarks>
		T CreateServiceDirect<T>(System.Type serviceInterface);

		/// <summary>
		/// Directly retrieves an instance of a multi-instance dependent service and passes its
		/// parent service through its constructor.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <param name="dependent">Instance of the parent service the created service depends on.</param>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <typeparam name="S">Type of parent service given by <paramref cref="dependent">dependent</paramref>.</typeparam>
		/// <returns>Instance of the service object.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only.
		/// </para>
		/// <para>
		/// <c>CreateServiceDirect</c> ignores any service substitutes, what means that the resulting object instance always will
		/// be of the requested service.
		/// </para>
		/// </remarks>
		T CreateDependentServiceDirect<T, S>(System.Type serviceInterface, S dependent);

		/// <summary>
		/// Directly retrieves an instance of a multi-instance dependent service and passes its two
		/// parent services through its constructor.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <param name="dep1">Instance of the first parent service the created service depends on.</param>
		/// <param name="dep2">Instance of the second parent service the created service depends on.</param>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <typeparam name="S1">Type of the first parent service given by <paramref cref="dep1">dep1</paramref>.</typeparam>
		/// <typeparam name="S2">Type of the second parent service given by <paramref cref="dep2">dep2</paramref>.</typeparam>
		/// <returns>Instance of the service object.</returns>
		/// <remarks>
		/// <para>This method creates instances of multi-instance services only.
		/// </para>
		/// <para>
		/// <c>CreateServiceDirect</c> ignores any service substitutes, what means that the resulting object instance always will
		/// be of the requested service.
		/// </para>
		/// </remarks>
		T CreateDependentServiceDirect2<T, S1, S2>(System.Type serviceInterface, S1 dep1, S2 dep2);

		/// <summary>
		/// Retrieves an instance of a single-instance service object.
		/// </summary>
		/// <typeparam name="T">Type of the returned service instance.</typeparam>
		/// <param name="serviceName">Registered service interface.</param>
		/// <returns>Instance of the service object, typed as set by the <typeparamref name="T">T</typeparamref> parameter.</returns>
		/// <remarks>
		/// <para>This method retrieves instances of single-instance services only. Please use
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.CreateService">CreateService</see> for multi-instance services.
		/// </para>
		/// <para>
		/// <c>GetService</c> resolves any service substitutes (see also
		/// <see cref="AWZhome.NQ.Core.NQServiceSubstituteAttribute">NQServiceSubstituteAttribute</see>). So if the requested
		/// service has been substituted by another service, this method will return an instance of that substituting service.
		/// </para>
		/// <para>
		/// GetService can't be called until all single-instance services are initialized. A service
		/// might suspend this lock during its own initialization by calling
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.SuspendServiceInitLock">SuspendServiceInitLock</see> method.
		/// </para>
		/// </remarks>
		T GetService<T>(System.Type serviceInterface);

		/// <summary>
		/// Creates all services in the given AttachList.
		/// </summary>
		/// <param name="attList">Name of AttachList.</param>
		/// <typeparam name="S">Type of attached services to return as an array.</typeparam>
		/// <returns>
		/// Array of all created service instances.
		/// </returns>
		S[] CreateAttachedServices<S>(string attList);

		/// <summary>
		/// Gets all services in the given AttachList, creating new instances of multi-instance services
		/// and returning common instances of single-instance services.
		/// </summary>
		/// <typeparam name="S">Type of attached services to return as an array.</typeparam>
		/// <param name="attList">Name of AttachList.</param>
		/// <param name="includeMultiInstServices">Set to <c>true</c> to handle multi-instance services.</param>
		/// <param name="includeSingleInstServices">Set to <c>true</c> to handle single-instance services.</param>
		/// <returns>Array of all attached services instances.</returns>
		S[] GetAttachedServices<S>(string attList, bool includeMultiInstServices, bool includeSingleInstServices);

		/// <summary>
		/// Creates all dependent services in the given AttachList.
		/// </summary>
		/// <typeparam name="T">Type of the returned service instances.</typeparam>
		/// <typeparam name="S">Type of the parent service of all attached services.</typeparam>
		/// <param name="attList">Name of AttachList</param>
		/// <param name="dependent">Instance of parent service to be used for initialization.</param>
		/// <returns>Created service instances.</returns>
		T[] CreateAttachedDepServices<T, S>(string attList, S dependent);

		/// <summary>
		/// Creates all dependent services in the given AttachList.
		/// </summary>
		/// <typeparam name="T">Type of the returned service instances.</typeparam>
		/// <typeparam name="S1">Type of the first parent service of all attached services.</typeparam>
		/// <typeparam name="S2">Type of the second parent service of all attached services.</typeparam>
		/// <param name="attList">Name of AttachList.</param>
		/// <param name="dep1">Instance of the first parent service.</param>
		/// <param name="dep2">Instance of the second parent service.</param>
		/// <returns>Created service instances.</returns>
		T[] CreateAttachedDepServices2<T, S1, S2>(string attList, S1 dep1, S2 dep2);

		/// <summary>
		/// Returns an array of all service interfaces an AttachList contains.
		/// </summary>
		/// <param name="listname">Name of AttachList.</param>
		/// <returns>Array of <see cref="System.Type">Type</see> objects for
		/// all service interfaces.</returns>
		System.Type[] GetAttachedServices(string listname);

		/// <summary>
		/// Returns an array of names of currently loaded components.
		/// </summary>
		/// <returns>Array of component names.</returns>
		string[] GetComponentList();

		/// <summary>
		/// Returns an array of all currently registered service interfaces.
		/// </summary>
		/// <returns>Array of <see cref="System.Type">Type</see> objects for
		/// all service interfaces.</returns>
		System.Type[] GetServiceList();

		/// <summary>
		/// Returns an array of names of all currently created AttachLists.
		/// </summary>
		/// <returns>Array of AttachList names.</returns>
		string[] GetAllAttachLists();

		/// <summary>
		/// Checks if a certain single-instance service is running.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface</param>
		/// <returns><c>true</c>, if the service is existing, <c>false</c> otherwise.</returns>
		bool IsServiceRunning(System.Type serviceInterface);

		/// <summary>
		/// Checks if a certain multi-instance service is registered and an instance can be created.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <returns><c>true</c>, if an instance of the service can be created, <c>false</c> otherwise.</returns>
		bool IsServiceCreatable(System.Type serviceInterface);

		/// <summary>
		/// Checks if a certain component is loaded.
		/// </summary>
		/// <param name="componentName">Name of component.</param>
		/// <returns><c>true</c>, if the component is loaded, <c>false</c> otherwise.</returns>
		bool IsComponentLoaded(string componentName);

		/// <summary>
		/// Returns information about a certain component encapsulated in an instance of
		/// <see cref="AWZhome.NQ.Core.INQComponentInfo">INQComponentInfo</see>.
		/// </summary>
		/// <param name="componentName">Name of component.</param>
		/// <returns>Instance of <see cref="AWZhome.NQ.Core.INQComponentInfo">INQComponentInfo</see>.</returns>
		INQComponentInfo GetComponentInfo(string componentName);

		/// <summary>
		/// Returns information about a certain service encapsulated in an instance of
		/// <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <returns>Instance of <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>.</returns>
		INQServiceInfo GetServiceInfo(System.Type serviceInterface);

		/// <summary>
		/// Returns information about a certain service from a service object.
		/// </summary>
		/// <param name="serviceObject">Instance of a service.</param>
		/// <returns>Instance of <see cref="AWZhome.NQ.Core.INQServiceInfo">INQServiceInfo</see>.</returns>
		INQServiceInfo GetServiceInfoFromObject(object serviceObject);

		/// <summary>
		/// Checks whether a service implements the specified service type.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface.</param>
		/// <param name="type">Type definition the service has to be checked for.</param>
		/// <returns><c>True</c>, if service implements the given type, <c>false</c> otherwise.</returns>
		bool IsServiceOfType(System.Type serviceInterface, System.Type type);

		/// <summary>
		/// Returns the interface of the service that is currently substituting the given service.
		/// </summary>
		/// <param name="serviceInterface">Registered service interface</param>
		/// <returns>
		/// Registered interface of substituting service or <c>null</c>, if the given service is
		/// not substituted.
		/// </returns>
		System.Type GetSubstitutingService(System.Type serviceInterface);

		/// <summary>
		/// Instructs the service to begin an operation, that is invokable through a method marked by
		/// <see cref="AWZhome.NQ.Core.NQServiceInvokeMethodAttribute">NQServiceInvokeMethodAttribute</see>
		/// or an implementation of <see cref="AWZhome.NQ.Core.INQInvokableService">INQInvokableService</see>.
		/// </summary>
		/// <param name="serviceObject"></param>
		void InvokeService(object serviceObject);

		/// <summary>
		/// Instructs the service to stop an operation through a method marked by
		/// <see cref="AWZhome.NQ.Core.NQServiceQuitMethodAttribute">NQServiceQuitMethodAttribute</see>
		/// or an implementation of <see cref="AWZhome.NQ.Core.INQInvokableService">INQInvokableService</see>.
		/// </summary>
		/// <param name="serviceObject"></param>
		void QuitService(object serviceObject);

		/// <summary>
		/// Exists the application firing the 
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.AppExitRequested">AppExitRequested</see>.
		/// </summary>
		/// <remarks>
		/// The ExitApplication method exits the process directly. GUI applications should perform
		/// a regular exit from the window message loop instead. By setting the 
		/// <see cref="AWZhome.NQ.Core.NQCancelEventArgs.Cancel">Cancel</see> property
		/// to <c>true</c> in AppExitRequested the exit can be aborted to end the message loop the
		/// proper way.
		/// </remarks>
		void ExitApplication();

		/// <summary>
		/// Returns the directory where all component assemblies are loaded from.
		/// </summary>
		string ComponentPath
		{
			get;
		}

		/// <summary>
		/// Returns the mode of the running NQ application.
		/// </summary>
		NQHostMode HostMode
		{
			get;
		}

		/// <summary>
		/// Returns the synchronization object of the service manager which can be used to
		/// synchronize threads.
		/// </summary>
		object SyncObject
		{
			get;
		}

		/// <summary>
		/// Does a thread and type safe call to the given delegate of a method without return value
		/// using the GUI thread's context in GUI mode.
		/// </summary>
		/// <typeparam name="P">Type of the delegate's parameter.</typeparam>
		/// <param name="method">The delegate object to be used for the call.</param>
		/// <param name="param">The method parameter.</param>
		/// <remarks>
		/// When in GUI mode (see also <see cref="AWZhome.NQ.Core.INQServiceManager.HostMode">HostMode</see>)
		/// the method marshals the call into the GUI thread's context. This is very useful for graphical
		/// Windows applications that have to access GUI elements from additional threads. If not in GUI mode
		/// the method creates a critical section around the call using the internal synchronization object (see
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.SyncObject">SyncObject</see>).
		/// </remarks>
		void InvokeSyncMethod<P>(NQSynchronizedProcDelegate<P> method, P param);

		/// <summary>
		/// Does a thread and type safe call to the given delegate using the GUI thread's
		/// context in GUI mode.
		/// </summary>
		/// <typeparam name="P">Type of the delegate's parameter.</typeparam>
		/// <typeparam name="R">Type of the delegate's return value.</typeparam>
		/// <param name="method">The delegate object to be used for the call.</param>
		/// <param name="param">The method parameter.</param>
		/// <returns>The return value of the called delegate.</returns>
		/// <remarks>
		/// When in GUI mode (see also <see cref="AWZhome.NQ.Core.INQServiceManager.HostMode">HostMode</see>)
		/// the method marshals the call into the GUI thread's context. This is very useful for graphical
		/// Windows applications that have to access GUI elements from additional threads. If not in GUI mode
		/// the method creates a critical section around the call using the internal synchronization object (see
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.SyncObject">SyncObject</see>).
		/// </remarks>
		R InvokeSyncMethod<P, R>(NQSynchronizedDelegate<P, R> method, P param);

		/// <summary>
		/// Returns the version display string that is saved in the component assembly's version resource.
		/// </summary>
		/// <param name="assembly">The assembly's description object.</param>
		/// <param name="productName">Product name to be displayed before the version string.</param>
		/// <returns>Full display string with the assembly version.</returns>
		string GetAssemblyVersionString(System.Reflection.Assembly assembly, string productName);

		/// <summary>
		/// Helper method to get the copyright information of an assembly.
		/// </summary>
		/// <param name="assembly">The assembly's description object.</param>
		/// <returns>A string with the displayable copyright information.</returns>
		string GetAssemblyCopyright(System.Reflection.Assembly assembly);

		/// <summary>
		/// Logs a message to the application protocol.
		/// </summary>
		/// <param name="logType">Type of the logged message.</param>
		/// <param name="logMessage">Message text. May include format definitions like in <see cref="System.String.Format"/></param>
		/// <param name="args">
		/// Additional arguments to be output in log,
		/// according to format definition in <paramref name="logMessage"/>.
		/// </param>
		void LogMessage(NQLogType logType, string logMessage, params object[] args);

		/// <summary>
		/// Logs an exception to the application protocol.
		/// </summary>
		/// <param name="logType">Type of the logged message.</param>
		/// <param name="logException">The exception object to be logged.</param>
		/// <remarks>
		/// This method logs the name and the message of the exception and also puts out the stack trace,
		/// if the command-line parameter <c>-ls</c> is set.
		/// </remarks>
		void LogMessage(NQLogType logType, System.Exception logException);

		/// <summary>
		/// Logs an exception from a service to the application protocol.
		/// </summary>
		/// <param name="fromService">Instance of the service that has initiated the log event.</param>
		/// <param name="logType">Type of the logged message.</param>
		/// <param name="logException">The exception object to be logged.</param>
		/// <remarks>
		/// This method logs the name and the message of the exception and also puts out the stack trace,
		/// if the command-line parameter <c>-ls</c> is set.
		/// </remarks>
		void LogMessage(object fromService, NQLogType logType, System.Exception logException);

		/// <summary>
		/// Logs a message from a service to the application protocol.
		/// </summary>
		/// <param name="sourceService">Instance of the service that has initiated the log event.</param>
		/// <param name="logType">Type of the logged message.</param>
		/// <param name="logMessage">Message text. May include format definitions like in <see cref="System.String.Format"/></param>
		/// <param name="args">
		/// Additional arguments to be output in log,
		/// according to format definition in <paramref name="logMessage"/>.
		/// </param>
		void LogMessage(object sourceService, NQLogType logType, string logMessage, params object[] args);

		/// <summary>
		/// Logs a message from a service to the application protocol.
		/// </summary>
		/// <param name="sourceService">Instance of the service that has initiated the log event.</param>
		/// <param name="logType">Type of the logged message.</param>
		/// <param name="logException">The exception object to be logged.</param>
		/// <param name="logMessage">Message text. May include format definitions like in <see cref="System.String.Format"/></param>
		/// <param name="args">
		/// Additional arguments to be output in log,
		/// according to format definition in <paramref name="logMessage"/>.
		/// </param>
		void LogMessage(object sourceService, NQLogType logType, System.Exception logException, string logMessage, params object[] args);

		/// <summary>
		/// Returns path and file name of the currently used log file.
		/// </summary>
		string LogFile
		{
			get;
		}

		/// <summary>
		/// Indicates whether the Service Manager has been initialized (then it's active) or destroyed (non-active).
		/// </summary>
		bool IsActive
		{
			get;
		}

		/// <summary>
		/// Gets/sets the current log level filter for
		/// <see cref="AWZhome.NQ.Core.INQServiceManager.MessageLogged">MessageLogged</see> events.
		/// </summary>
		NQLogType LogEventFilter
		{
			get;
			set;
		}

		/// <summary>
		/// Gets/sets the current log level filter for the Service Manager's own log file.
		/// </summary>
		NQLogType LogFileFilter
		{
			get;
			set;
		}
	}
}
